package com.inspur.edp.common.expr.evaluator;

import com.inspur.edp.common.expr.Express;
import com.inspur.edp.common.expr.ExpressDSLGeneratorMgr;
import com.inspur.edp.common.expr.ast.ASTContext;
import com.inspur.edp.common.expr.ast.AbsASTContext;
import com.inspur.edp.common.expr.ast.CompileUnitParser;
import com.inspur.edp.common.expr.expresses.constant.StringConstExpr;
import com.inspur.edp.common.expr.expresses.node.NodeVariableExpr;
import com.inspur.edp.common.expr.parser.ASTParser;
import com.inspur.edp.common.expr.visitor.JavaVisitor;
import com.inspur.edp.common.expr.visitor.field.HashMapFieldVisitor;
import com.inspur.edp.common.type.Field;
import com.inspur.edp.common.type.Type;
import com.inspur.edp.common.type.TypeRefer;
import com.inspur.edp.common.type.cache.TypeThreadCache;
import com.inspur.edp.common.type.utils.TypeUtil;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;

import java.util.*;

/**
 * @author lizhaorui
 * @date 2025/8/15
 * @description
 */

public class EvaluatorService {

    public static ExpressEvaluator build(ASTContext astContext, Express express) {
        if (express instanceof StringConstExpr) {
            return new StringConstEvaluator(((StringConstExpr) express).getValue());
        }
        if (express instanceof NodeVariableExpr) {
            NodeVariableExpr nodeVariableExpr = (NodeVariableExpr) express;
            List<String> fields = nodeVariableExpr.getFields();
            if (fields == null || fields.size() == 0) {
                return new NodeParamEvaluator(nodeVariableExpr.getNodeCode(), nodeVariableExpr.getVariable());
            }
        }
        AbsASTContext absASTContext = (AbsASTContext) astContext;
        Collection<String> allImports = absASTContext.getAllImports();
        String expressText = ExpressDSLGeneratorMgr.generateDsl(astContext, express);
        ExpressEvaluator expressEvaluator = build(astContext, expressText, absASTContext.getAllImports());
        absASTContext.setAllImports(allImports);
        return expressEvaluator;
    }

    public static ExpressEvaluator build(ASTContext astContext, String content) {
        return build(astContext, content, new ArrayList<>());
    }

    private static ExpressEvaluator build(ASTContext astContext, String content, Collection<String> imports) {
        CompileUnitParser.ExpressContext expressContext = ASTParser.parse(content).express();

        List<String> variableNames = new ArrayList<>();
        deepSearch(expressContext, variableNames);
        variableNames = filterVariableNames(astContext, variableNames);
        StringBuilder dslSb = new StringBuilder();
        //1、imports
        Type contextType = buildVariableMapType(astContext, variableNames);
        try {
            TypeThreadCache.add(contextType);
            String contextTypeUrl = TypeUtil.getTypeUrl(contextType);
            imports.add(contextTypeUrl);
            String contextTypeName = TypeUtil.getTypeCode(contextTypeUrl);
            for (String importStr : imports) {
                String importTypeCode = TypeUtil.getTypeCode(importStr);
                dslSb.append(String.format("import {%s} from \"%s\";", importTypeCode, importStr));
            }

            //2、类定义
            String className = "Exp_" + UUID.randomUUID().toString().replace("-", "");
            dslSb.append(String.format("\n@dslClass({ code : \"%s\" })", className));
            dslSb.append(String.format("\nexport class %s{ ", className));
            dslSb.append(String.format("\npublic static run(  _context_ : %s) : any {", contextTypeName));
            for (String variableName : variableNames) {
                dslSb.append(String.format("\nlet %s=_context_.%s;", variableName, variableName));
            }
            if (expressContext instanceof CompileUnitParser.AssignValExprContext) {
                dslSb.append(String.format("\n %s ;", content));
                dslSb.append(String.format("\nreturn %s ;", "null"));
            } else {
                dslSb.append(String.format("\nreturn %s ;", content));
            }
            dslSb.append("\n}");
            dslSb.append("\n}");
            //3、转成JavaCode
            JavaVisitor javaVisitor = new JavaVisitor();
            String javaCode = javaVisitor.generateJava(dslSb.toString());
            return new ScriptEvaluator(javaCode, className);
        } finally {
            TypeThreadCache.remove(contextType);
        }
    }

    private static Type buildVariableMapType(ASTContext astContext, List<String> variableNames) {
        Type contextType = new Type();
        contextType.setTypeOptCode("java.util.Map");
        String uuid = UUID.randomUUID().toString().replace("-", "_");
        String typeId = "ContextType_" + uuid;
        contextType.setSource(TypeRefer.TEMP_SOURCE);
        contextType.setTypeId(typeId);
        contextType.setFields(new ArrayList<>());
        for (String variableName : variableNames) {
            if (astContext.containVarName(variableName)) {
                Field contextField = new Field();
                contextField.setCode(variableName);
                contextField.setType(astContext.getVarType(variableName));
                contextField.setAccessKind(HashMapFieldVisitor.KIND);
                contextType.getFields().add(contextField);
            }
        }
        return contextType;
    }

    private static List<String> filterVariableNames(ASTContext astContext, List<String> variableNames) {
        List<String> names = new ArrayList<>();
        for (String variableName : variableNames) {
            if (astContext.containVarName(variableName)) {
                names.add(variableName);
            }
        }
        return names;
    }

    public static void deepSearch(ParserRuleContext parserRuleContext, List<String> variableNames) {
        if (parserRuleContext instanceof CompileUnitParser.SimpleNameExprContext) {
            CompileUnitParser.SimpleNameExprContext simpleNameExprContext = (CompileUnitParser.SimpleNameExprContext) parserRuleContext;
            String variableName = simpleNameExprContext.SimpleName().getText();
            if (!variableNames.contains(variableName)) {
                variableNames.add(variableName);
            }
        } else {
            List<ParseTree> trees = parserRuleContext.children;
            if (trees != null && trees.size() > 0) {
                for (ParseTree tree : trees) {
                    if (tree instanceof ParserRuleContext) {
                        deepSearch((ParserRuleContext) tree, variableNames);
                    }
                }
            }
        }
    }

    public static void putDependVars(ASTContext context, Express express, Map<String, ExpressEvaluator> dependMap) {
        String expressText = ExpressDSLGeneratorMgr.generateDsl(context, express);
        putDependVars(context, expressText, dependMap);
    }

    public static void putDependVars(ASTContext context, String expressText, Map<String, ExpressEvaluator> dependMap) {
        CompileUnitParser.ExpressContext expressContext = ASTParser.parse(expressText).express();
        List<String> variableNames = new ArrayList<>();
        EvaluatorService.deepSearch(expressContext, variableNames);
        variableNames = EvaluatorService.filterVariableNames(context, variableNames);
        for (String variableName : variableNames) {
            if (!dependMap.containsKey(variableName)) {
                dependMap.put(variableName, new DirectEvaluator(variableName));
            }
        }
    }

}